package com.supermarket.api.common.filters;

import com.supermarket.api.common.BaseResponse;
import com.supermarket.api.common.ErrorMessage;
import com.supermarket.api.common.redis.RedisConstants;
import com.supermarket.api.common.redis.RedisOperate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.util.StringUtils;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;

/**
 * token 验证
 * @author li
 */
@Slf4j
@Configuration
@WebFilter(filterName = "tokenFilter",urlPatterns = {"/*"})
public class TokenFilter implements Filter {

    @Autowired
    private RedisOperate redisOperate;

    /**
     * 头部token值
     */
    private static final String TOKEN = "token";

    /**
     * 需要验证的匹配模式
     */
    private static Pattern  PASS = Pattern.compile("(^/admin/*)");


    /**
     * 获取token
     * @param httpRequest
     * @return
     */
    private String getToken(HttpServletRequest httpRequest){
        String token = "";
        /**
         * 从头部取token
         */
        token  = httpRequest.getHeader(TOKEN);
        /**
         * 头部找不到token，再从cookie中取
         */
        if("".equals(token)){
            Cookie[] cookies = httpRequest.getCookies();
            if(cookies!=null&&cookies.length!=0){
                for(Cookie c: cookies){
                    if(c.getName().equals(TOKEN)){
                        token=c.getValue();
                    }
                }
            }
        }
        return token;
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
        HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
        String url = httpRequest.getRequestURI().substring(httpRequest.getContextPath().length());
        /**
         * 复杂请求的预请求，我们这里是直接放行
         */
        if (HttpMethod.OPTIONS.matches(httpRequest.getMethod())) {
            httpResponse.setStatus(HttpServletResponse.SC_OK);
            filterChain.doFilter(servletRequest,servletResponse);
            return;
        }
        /**
         * 请求路径是否允许
         */
        Matcher matcher = PASS.matcher(url);
        if(matcher.find()){
            String token = getToken(httpRequest);
            //请求中获取token失败
            if(StringUtils.isEmpty(token)){
                errorPrintWriter(httpResponse,"token不存在");
            }else {
                String key = RedisConstants.ACCESS_TOKE+token;
                String value = redisOperate.get(key);
                //Redis查询token不存在
                if(StringUtils.isEmpty(value)){
                    errorPrintWriter(httpResponse,"token失效");
                }else {
                    UserCacheManage.setUserCache(value);
                    filterChain.doFilter(servletRequest,servletResponse);
                }
            }
        }else {
            filterChain.doFilter(servletRequest,servletResponse);
        }
    }

    /**
     * 返回token错误信息
     * 浏览器用utf8来解析返回的数据
     * @param httpResponse     返回参数
     * @param msg              错误信息
     * @throws IOException
     */
    void errorPrintWriter(HttpServletResponse httpResponse , String msg) throws IOException {

        httpResponse.setContentType(APPLICATION_JSON_VALUE);
        httpResponse.setHeader("Access-Control-Allow-Origin","*");
        httpResponse.setHeader("Cache-Control","no-cache");
        httpResponse.setCharacterEncoding("UTF-8");
        httpResponse.setStatus(HttpServletResponse.SC_OK);
        PrintWriter out = httpResponse.getWriter();
        out.write(BaseResponse.errorJson(ErrorMessage.ERR_TOKEN_ERROR.getCode(),msg));

    }

}
